
package com.compuvest.admin.update.v1

import org.apache.commons.fileupload.FileItem
import org.apache.commons.fileupload.FileUploadException
import org.apache.commons.fileupload.disk.DiskFileItemFactory
import org.apache.commons.fileupload.servlet.ServletFileUpload

import javax.servlet.ServletConfig

import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import javax.servlet.annotation.WebServlet

import org.vasil.update.mongodb.DBService

@WebServlet("/transactions/UpdateXMLItems")
class UploadXMLItems extends HttpServlet {

    final static int XML_SIZE = 2097152 // 2M

    def mysql, nosql

    def void init(ServletConfig config) {
	super.init(config)

        mysql = new SQLService()
        nosql = new DBService()
    }

    def void processRequest(request, response) {

        def start = System.currentTimeMillis()

        def newitems = doIt(request)

        def xmlstatus = returnItemsStatus(System.currentTimeMillis() - start, newitems)
        //println "------xmlstatus\n${xmlstatus}"

        response.setContentType("text/xml;charset=UTF-8")
        def out = response.getWriter()
        out.print(xmlstatus)
    }

    def doIt(request) {

        def newitems = [:]
        if(ServletFileUpload.isMultipartContent(request)) {

            def xmlBody
            //
            def diskFileItemFactory = new DiskFileItemFactory()
            diskFileItemFactory.setSizeThreshold(XML_SIZE) // the unit is bytes in memory

            def servletFileUpload = new ServletFileUpload(diskFileItemFactory)
            servletFileUpload.setSizeMax(XML_SIZE) // the unit is bytes


            def fileItemsList
            try {
                fileItemsList = servletFileUpload.parseRequest(request)
            }
            catch(e) {
                println "---------UploadXMLItems---------\n${e}" +
                        ">>>fileItemsList=[${fileItemsList.toString()}]\n" +
                        "--------------------------------\n"
                return
            }
            //println ">>>fileItemsList=[${fileItemsList.toString()}]"

            for(fileItem in fileItemsList) {
                if(!fileItem.isFormField() && fileItem.getSize()) {
                    xmlBody = fileItem.getString()
                    break
                }
            }
            //println ">>>xBody=[${xmlBody}]"

//------------------------------------------------

            // xml do
            def parser = new XmlSlurper()
            def root
            try {
                root = parser.parseText(xmlBody)
            }
            catch(e) {
                println ">>>UploadXMLItems:Bad XML file xmlBody=[${xmlBody}]"
                return
            }
            //printXML(root)

            // block 1
            def rootname = root.name()
            if(rootname == "items") {
                //println ">>> items"
                def accwareidsPrice = new StringBuilder(), accwareidsDesc = new StringBuilder(), accwareidsDelete = new StringBuilder() // form accwareid0,accwareid1 ... accwareidn
                def attraccwareid, attraction, udesc
                root.item.each { item->

                    try {
                        attraccwareid = item.@accwareid.text()
                        attraction = item.@action.text()

                        if(attraction == "price") {
                            accwareidsPrice << (accwareidsPrice.size() ? ',' : '') << "'" << attraccwareid << "'"

                            newitems[attraccwareid] =
                                new Item(
                                    field: [
                                        costprice:  item.costprice.text() as Double,
                                        sellprice:  item.sellprice.text() as Double,
                                        reslprice:  item.reslprice.text() as Double,
                                        quantity:   item.qty.text() as Integer,
                                        stock:      getYesNo(item.stock),
                                        active:     'Y'
                                    ],
                                    utils: [
                                        action: attraction
                                    ]
                            )
                        }
                        else if(attraction == "desc") { // full description
                            //def start = System.currentTimeMillis()
                            accwareidsDesc << (accwareidsDesc.size() ? ',' : '') << "'" << attraccwareid << "'"

                            //udesc = URLDecoder.decode(item.desc.toString(), "UTF-8")
                            def url = "http://10.0.1.93/EditorXML/EtilizeXML.ashx?OPR=10&SKUBM=${attraccwareid}"
                            udesc = url.toURL().text

                            newitems[attraccwareid] =
                                new Item(
                                    category: [
                                        parentid:       item.category.parentid.text(),
                                        parentname:     item.category.parentname.text(),
                                        categoryid:     item.category.categoryid.text(),
                                        catname:        item.category.catname.text(),
                                        prefname1:      clean(item.category.prefname1.text()),
                                        prefname2:      clean(item.category.prefname2.text()),
                                        prefname3:      clean(item.category.prefname3.text()),
                                        prefname4:      clean(item.category.prefname4.text()),
                                        prefname5:      clean(item.category.prefname5.text())
                                    ],
                                    vendor: [
                                        alias:          item.vendor.alias.text(),
                                        name:           clean(item.vendor.name.text())
                                    ],
                                    field: [
                                        costprice:      item.costprice.text() as Double,
                                        sellprice:      item.sellprice.text() as Double,
                                        reslprice:      item.reslprice.text() as Double,
                                        stock:          getYesNo(item.stock),
                                        itemname:       clean(item.itemname.text()),
                                        advname:        setLimitLength(clean(item.advname.text()), 70),
                                        mfrname:        setLimitLength(cleanSpace(item.mfrname.text()), 35),
                                        mfrnumber:      setLimitLength(cleanSpace(item.mfrnumber.text()), 30),
                                        advprice:       getYesNo(item.advprice),
                                        mfrlink:        setLimitLength(item.mfrlink.text().replaceAll(/http:\/\//, '').replaceAll(/https:\/\//, '').replaceAll(/ftp:\/\//, ''), 128),
                                        packinclude:    setLimitLength(clean(item.packinclude.text()), 255),
                                        packcomment:    setLimitLength(clean(item.packcomment.text()), 512),
                                        stockdate:      item.stockdate.text(),
                                        weight:         item.weight.text()     as Double,
                                        reslprice1:     item.reslprice1.text() as Double,
                                        reslprice2:     item.reslprice2.text() as Double,
                                        reslprice3:     item.reslprice3.text() as Double,
                                        reslqty2:       item.reslqty2.text()   as Integer,
                                        reslqty3:       item.reslqty3.text()   as Integer,
                                        drone:          getBoolean(item.drone),
                                        wtymask:        item.wtymask.text()    as Integer,
                                        wtyprice1:      item.wtyprice1.text()  as Double,
                                        wtyprice2:      item.wtyprice2.text()  as Double,
                                        wtyprice3:      item.wtyprice3.text()  as Double,
                                        googlegroup:    item.googlegroup ? setLimitLength(item.googlegroup.text(), 15) : '',
                                        active:         'Y'
                                    ],
                                    quantity: [
                                        qty:            item.qty.text() as Integer
                                    ],
                                    fdesc: [
                                        desc:           udesc,
                                        size:           udesc.length(),
                                        etilid:         0L
                                    ],
                                    pref: [
                                        pref1:          setLimitLength(clean(item.pref1.text()), 30),
                                        pref2:          setLimitLength(clean(item.pref2.text()), 30),
                                        pref3:          setLimitLength(clean(item.pref3.text()), 30),
                                        pref4:          setLimitLength(clean(item.pref4.text()), 30),
                                        pref5:          setLimitLength(clean(item.pref5.text()), 30)
                                    ],
                                    advert: [
                                        advmfrname:     setLimitLength(cleanSpace(item.advmfrname.text()), 35),
                                        advmfrnumber:   setLimitLength(cleanSpace(item.advmfrnumber.text()), 30),
                                        keywords:       clean(item.keywords.text()),
                                        cnet:           getBoolean(item.advert.cnet),
                                        grabber:        getBoolean(item.advert.grabber),
                                        bizrate:        getBoolean(item.advert.bizrate),
                                        nextag:         getBoolean(item.advert.nextag),
                                        shopping:       getBoolean(item.advert.shopping),
                                        powersource:    getBoolean(item.advert.powersource),
                                        froogle:        getBoolean(item.advert.froogle),
                                        cj:             getBoolean(item.banner.cj),
                                        gadgetpage:     getBoolean(item.banner.gadgetpage),
                                        upccode:        setLimitLength(item.upccode.text(), 15)
                                    ],
                                    banner: [
                                        special:        getBoolean(item.banner.special),
                                        closeout:       getBoolean(item.banner.closeout),
                                        comingsoon:     getBoolean(item.banner.comingsoon),
                                        bestprice:      getBoolean(item.banner.bestprice),
                                        firstpage:      getBoolean(item.banner.firstpage),
                                        categorypage:   getBoolean(item.banner.categorypage),
                                        ebay:           getBoolean(item.banner.ebay),
                                        lot:            getBoolean(item.lot)
                                    ],
                                    utils: [
                                        action:         attraction,
                                        accwareid:      attraccwareid,
                                        catid:          0,
                                        vendid:         2, // CVS
                                        itemid:         0
                                    ],
                                    json: [
                                        imgs:           '',
                                        namea:          '',
                                        nameb:          '',
                                        pkeywrd:        '',
                                        pics:           ''
                                    ],
                                    images: [ // images from bookmaker
                                        url0:       item.images.url0.text(),
                                        url1:       item.images.url1.text(),
                                        url2:       item.images.url2.text(),
                                        url3:       item.images.url3.text()
                                    ]
                            )
                            //println "1 Desc Time: ${System.currentTimeMillis() - start}ms."
                        } //attraction == "desc"
                        else if(attraction == "delete") { // delete item
                            accwareidsDelete << (accwareidsDelete.size() ? ',' : '') << "'" << attraccwareid << "'"

                            newitems[attraccwareid] = new Item(
                                    field: [
                                        active: 'D',
                                    ],
                                    utils: [
                                        action: attraction
                                    ]
                            )
                        } //attraction == "delete"

                    }
                    catch(e) {
                        newitems[attraccwareid] = new Item( utils: [ action: attraction ] )
                        def eitem = newitems.get(attraccwareid)
                        eitem.setResult("Error", "Error", "Bad item in block 1: ${attraccwareid}")
                    }
                } // root.item.each
                //printXML(newitems)

                // get items from mysql
                if(accwareidsPrice.size()) {
                    //println "#>price=${accwareidsPrice}"

                    def olditems = mysql.getPriceItems(accwareidsPrice)

                    // test price action for need update or not
                    def oitem, needupdate
                    newitems.each { accwareid, nitem ->

                        try {
                        if(nitem.utils['action'] == "price") {
                            oitem = olditems.get(accwareid)

                            //printTestPrice(accwareid, nitem, oitem)
                            if(oitem) {

                                needupdate = isItemNewEqualsOld(nitem, oitem)

                                nitem.needupdate['qty'] = nitem.quantity['qty'] != oitem.quantity['qty']

                                if(needupdate || nitem.needupdate['qty']) {

                                    nitem.setResult("Ok", "Update", "Update Price ${accwareid}")
                                }
                                else {
                                    nitem.setResult("NoNeed", "Update", "No need update price ${accwareid}")
                                }
                            }
                            else { // oitem == null
                                nitem.setResult("NotFind", "Error", "Not find item ${accwareid}")
                            }
                        }
                    }
                    catch(e) {
                        nitem.setResult("Error", "Error", "Bad price item: ${accwareid}")
                        return
                    }
                    } // foreach

                    mysql.doBatchPrice(newitems)
                }
                if(accwareidsDesc.size()) {
                    //println "#>desc=${accwareidsDesc}"
                    //def start = System.currentTimeMillis()
                    
                    def olditems = mysql.getDescItems(accwareidsDesc)
                    
                    // test desc action for need update
                    def oitem, needupdate
                    newitems.each { accwareid, nitem ->
                        
                        try {
                            if(nitem.utils['action'] == "desc") {
                                oitem = olditems.get(accwareid)
                                
                                if(oitem) { // update
                                    //println "#>update accwareid=${accwareid}"
                                    
                                    // if no need update category or vendor - use old
                                    nitem.utils['catid']  = oitem.utils['catid']
                                    nitem.utils['vendid'] = oitem.utils['vendid']
                                    nitem.utils['itemid'] = oitem.utils['itemid']
                                    
                                    nitem.needupdate['qty'] = nitem.quantity['qty'] != oitem.quantity['qty']
                                    
                                    needupdate = isItemNewEqualsOld(nitem, oitem)
                                    
                                    if(needupdate || nitem.needupdate['qty']) {
                                        nitem.setResult("Ok", "Update",
                                        "Update item ${accwareid} " +
                                        "[${nitem.needupdate['category'] ? 'category' : ''} " +
                                        "${nitem.needupdate['vendor']    ? 'vendor' : ''} " +
                                        "${nitem.needupdate['desc']      ? 'desc' : ''} " +
                                        "${nitem.needupdate['pref']      ? 'pref' : ''} " +
                                        "${nitem.needupdate['advert']    ? 'advert' : ''} " +
                                        "${nitem.needupdate['banner']    ? 'banner' : ''} " +
                                        "${nitem.needupdate['qty']       ? 'quantity' : ''} " +
                                        "${nitem.needupdate['field']     ? 'field' : ''}]"
                                        )
                                        
                                        //printTestDesc(accwareid, nitem, oitem)
                                        doDescription(nitem)
                                    }
                                    else {
                                        nitem.setResult("NoNeed", "Update", "No need update item ${accwareid}")
                                    }
                                }
                                else {  // insert
                                    nitem.setResult("Ok", "Create", "Insert new item ${accwareid}")
                                    
                                    // when new item always update
                                    nitem.needupdate['vendor'] = nitem.needupdate['category'] = true
                                    
                                    //printTestDescNew(accwareid, nitem)
                                    doDescription(nitem)
                                }
                            }
                        }
                        catch(e) {
                            nitem.setResult("Error", "Error", "Bad desc item: ${accwareid}")
                            println "#>accwareid=${accwareidsDesc}\nerror=${e}"
                            return
                        }
                    } // each
                    //println "Desc Time: ${System.currentTimeMillis() - start}ms."
                    
                    //mysql.doBatchDesc(newitems)
                    nosql.doInsertItems(newitems)
                } // accwareidsDesc.size()
                if(accwareidsDelete.size()) {
                    //println "#>delete=${accwareidsDelete}"
                    
                    def olditems = mysql.getDeleteItems(accwareidsDelete)
                    
                    // test need delete
                    def oitem, needupdate
                    newitems.each { accwareid, nitem ->
                        
                        try {
                            if(nitem.utils['action'] == "delete") {
                                oitem = olditems.get(accwareid)
                                
                                //printTestDelete(accwareid, nitem, oitem)
                                if(oitem) {
                                    
                                    needupdate = isItemNewEqualsOld(nitem, oitem)
                                    
                                    if(needupdate) {
                                        nitem.setResult("Ok", "Delete", "Delete item ${accwareid}")
                                    }
                                    else {
                                        nitem.setResult("NoNeed", "Delete", "No need delete item ${accwareid}")
                                    }
                                }
                                else {
                                    nitem.setResult("NotFind", "Delete", "Not find item ${accwareid}")
                                }
                            }
                        }
                        catch(e) {
                            nitem.setResult("Error", "Error", "Bad delete item: ${accwareid}")
                            return
                        }
                    } // each
                    
                    //mysql.doBatchDelete(newitems)
                    nosql.doDeleteItems(newitems)
                }
            } //rootname == "items"

//            println "newitem2=" << newitem.toString()
        }

        return newitems
    }

    def doDescription(nitem) {

        def parser = new XmlSlurper()
        def etilizedesc
        try {
            etilizedesc = parser.parseText(nitem.fdesc.desc)
        }
        catch(e) {
            nitem.setResult("Error", "Error", "Bad Etilize xml")
            //println "Bad etilize xml"
            return
        }

        if('EMPTY' == etilizedesc.D.text()) {
            nitem.setResult("Error", "Error", "Etilize xml EMPTY")
            //println "Etilize xml EMPTY"
            return
        }

        nitem.fdesc['etilid'] = etilizedesc.@PRODETID.text() as Long
        nitem.json['namea']   = clean(etilizedesc.NAMEA.text())
        nitem.json['nameb']   = clean(etilizedesc.NAMEB.text())
        nitem.json['minfo']   = clean(etilizedesc.MINFO.text())
        nitem.json['psiml']   = etilizedesc.PSIML.D.text()
        nitem.json['paccl']   = etilizedesc.PACCL.D.text()
        nitem.json['pkeywrd'] = etilizedesc.PKEYWRD.text()

        def mspec = new StringBuilder(), idx = 0
        mspec << "name:\"\",attr:{"
        etilizedesc.MSPEC.S.M.each { m ->
            mspec << (idx++ ? ',' : '') << "\"${clean(m.L.text())}\":\"${clean(m.D.text())}\""
        }
        mspec << "}"
        nitem.json['mspec'] = mspec

        def espec = new StringBuilder(), idy = 0
        etilizedesc.ESPEC.S.each { s ->
            espec << (idy++ ? ',' : '') << "{name:\"${clean(s.T.text())}\",attr:{"
            idx = 0
            s.M.each { m ->
                espec << (idx++ ? ',' : '') << "\"${clean(m.L.text())}\":\"${clean(m.D.text())}\""
            }
            espec << "}}"
        }
        nitem.json['espec'] = espec

        idx = 0
        def sattr = new StringBuilder()
        etilizedesc.SATTR.D.each { d ->
            sattr << (idx++ ? ',' : '') << "\"${clean(d.@ATTR.text())}\":\"${clean(d.text())}\""
        }
        nitem.json['sattr'] = sattr

        Image image = new Image(accwareid: nitem.utils.accwareid)

        etilizedesc.IMG.D.each { d ->

            switch(d.@TPIMG.text()) {
                case '300':
                    image.imgs['0'] = d.text()
                    break
                case 'Front':
                    image.imgs['front'] = d.text()
                    break
                case 'Right':
                    image.imgs['right'] = d.text()
                    break
                case 'Left':
                    image.imgs['left'] = d.text()
                    break
                case 'Rear':
                    image.imgs['rear'] = d.text()
                    break
                case 'Top':
                    image.imgs['top'] = d.text()
                    break
                case 'Bottom':
                    image.imgs['bottom'] = d.text()
                    break
                case 'Manufacturer-Brochure':
                    image.pdf['brochure'] = d.text()
                    break
                case 'User-Manual':
                    image.pdf['manual'] = d.text()
                    break
            }
        }

        // try get images from bookmaker
        if(!image.imgs['front'] && !nitem.images.url1.isEmpty()) {
            image.imgs['front'] = nitem.images.url1
        }
        if(!image.imgs['right'] && !nitem.images.url2.isEmpty()) {
            image.imgs['right'] = nitem.images.url2
        }
        if(!image.imgs['left'] && !nitem.images.url3.isEmpty()) {
            image.imgs['left'] = nitem.images.url3
        }

        // set front default image
        if(!image.imgs['0'] && !nitem.images.url0.isEmpty()) {
            image.imgs['0'] = nitem.images.url0
        }
        else if(!image.imgs['0'] && image.imgs['front']) {
            image.imgs['0'] = image.imgs['front']
        }
        else if(!image.imgs['0'] && image.imgs['right']) {
            image.imgs['0'] = image.imgs['right']
        }
        else if(!image.imgs['0'] && image.imgs['left']) {
            image.imgs['0'] = image.imgs['left']
        }
        if(!image.imgs['0']) {
            image.imgs['0'] = "http://10.0.2.18/defcat/${nitem.category['categoryid']}.jpg"
        }

        //println "image=${image.imgs}"
        nitem.json.imgs = image.getJson()
        nitem.json.pics = image.getPictures()
        //nitem.json['pdf'] = image.getManual()

    }

    def returnItemsStatus(time, nitems) {

        def xml = new StringBuilder()
        xml << "<?xml version='1.0' encoding='UTF-8'?>"
        xml << "<items time='${time}'>"
        nitems.each { accwareid, item ->
            xml << "<item accwareid='${accwareid}' action='${item.utils['action']}'>"
            xml << "<status result='${item.getResulttype()}'>${item.getResultmessage()}</status>"
            xml << "</item>"
        }
        xml << "</items>"

        return xml.toString()
    }

    def printTestPrice(accwareid, nitem, oitem) {

        if(!oitem) return

        def startEvent = System.currentTimeMillis()

        def outp = new StringBuilder()
        outp << "accwareid: ${accwareid} action: ${nitem.utils['action']}"
        outp << "\n            new      old"
        outp << "\nnew == old : ${isItemNewEqualsOld(nitem, oitem)}"
        nitem.field.each { name, value ->
            outp << "\n${name} : ${value} ${(value == oitem.field[name] ? '==' : '!=')} ${oitem.field[name]}"
        }
        outp << "\ntime : ${System.currentTimeMillis() - startEvent}ms"

        println outp
    }

    def printTestDesc(accwareid, nitem, oitem) {

        if(!oitem) return

        def startEvent = System.currentTimeMillis()

        def dash = '------------------'
        def outp = new StringBuilder()
        outp << "accwareid: ${accwareid} action: ${nitem.utils['action']}"
        outp << "\n\t\t\tnew\t\told"

        outp << "\n${dash}category need update? ${nitem.needupdate['category']}"
        nitem.category.each { name, value ->
            outp << "\n\t${name} : ${value} ${(value == oitem.category[name] ? '==' : '!=')} ${oitem.category[name]}"
        }

        outp << "\n${dash}vendor need update? ${nitem.needupdate['vendor']}"
        nitem.vendor.each { name, value ->
            outp << "\n\t${name} : ${value} ${(value == oitem.vendor[name] ? '==' : '!=')} ${oitem.vendor[name]}"
        }

        outp << "\n${dash}fields need update? : ${nitem.needupdate['field']}"
        nitem.field.each { name, value ->
            outp << "\n\t${name} : ${value} ${(value == oitem.field[name] ? '==' : '!=')} ${oitem.field[name]}"
        }

        outp << "\n${dash}quantity need update? : ${nitem.needupdate['qty']}"
        outp << "\n\tqty : ${nitem.quantity['qty']} ${(nitem.quantity['qty'] == oitem.quantity['qty'] ? '==' : '!=')} ${oitem.quantity['qty']}"

        outp << "\n${dash}fdesc need update? ${(nitem.fdesc.size != oitem.fdesc.size)}"
        outp << "\n\tdesc size : ${nitem.fdesc.size} ${(nitem.fdesc.size == oitem.fdesc.size ? '==' : '!=')} ${oitem.fdesc.size}"

        outp << "\n${dash}advert need update? ${nitem.needupdate['advert']}"
        nitem.advert.each { name, value ->
            outp << "\n\t${name} : ${value} ${(value == oitem.advert[name] ? '==' : '!=')} ${oitem.advert[name]}"
        }

        outp << "\n${dash}pref need update? ${nitem.needupdate['pref']}"
        nitem.pref.each { name, value ->
            outp << "\n\t${name} : ${value} ${(value == oitem.pref[name] ? '==' : '!=')} ${oitem.pref[name]}"
        }

        outp << "\n${dash}banner need update? ${nitem.needupdate['banner']}"
        nitem.banner.each { name, value ->
            outp << "\n\t${name} : ${value} ${(value == oitem.banner[name] ? '==' : '!=')} ${oitem.banner[name]}"
        }

        outp << "\n${dash}utils"
        nitem.utils.each { name, value ->
            outp << "\n\t${name}: ${value}"
        }

        outp << "\n${dash}images"
        nitem.images.each { name, value ->
            outp << "\n\t${name}\t: ${value}"
        }

        outp << "\n${dash}update"
        nitem.needupdate.each { name, value ->
            outp << "\n\t${name}\t: ${value}"
        }
        outp << "\ntime : ${System.currentTimeMillis() - startEvent}ms"

        println outp
    }

    def printTestDescNew(accwareid, nitem) {

        def startEvent = System.currentTimeMillis()

        def dash = '------------------'
        def outp = new StringBuilder()
        outp << "accwareid: ${accwareid} action: ${nitem.utils['action']}"
        outp << "\n\t\tnew"

        outp << "\n${dash}category"
        nitem.category.each { name, value ->
            outp << "\n\t${name} : ${value}"
        }

        outp << "\n${dash}vendor"
        nitem.vendor.each { name, value ->
            outp << "\n\t${name} : ${value}"
        }

        outp << "\n${dash}fields"
        nitem.field.each { name, value ->
            outp << "\n\t${name} : ${value}"
        }

        outp << "\n${dash}quantity\n\t${nitem.quantity['qty']}"

        outp << "\n\tdesc size : ${nitem.fdesc.size}"

        outp << "\n${dash}advert"
        nitem.advert.each { name, value ->
            outp << "\n\t${name} : ${value}"
        }

        outp << "\n${dash}pref"
        nitem.pref.each { name, value ->
            outp << "\n\t${name} : ${value}"
        }

        outp << "\n${dash}banners"
        nitem.banner.each { name, value ->
            outp << "\n\t${name} : ${value}"
        }

        outp << "\n${dash}utils"
        nitem.utils.each { name, value ->
            outp << "\n\t${name}:\t ${value}"
        }
        outp << "\n${dash}update"
        nitem.needupdate.each { name, value ->
            outp << "\n\t${name}\t: ${value}"
        }
        outp << "\ntime : ${System.currentTimeMillis() - startEvent}ms"

        println outp
    }

    def printTestDelete(accwareid, nitem, oitem) {

        if(!oitem) return

        def startEvent = System.currentTimeMillis()

        def outp = new StringBuilder()
        outp << "accwareid: ${accwareid} action: ${nitem.utils['action']}"
        outp << "\n  new      old"
        outp << "\nnew == old : ${isItemNewEqualsOld(nitem, oitem)}"
        nitem.field.each { name, value ->
            outp << "\n${name} : ${value} ${(value == oitem.field[name] ? '==' : '!=')} ${oitem.field[name]}"
        }
        outp << "\ntime : ${System.currentTimeMillis() - startEvent}ms"

        println outp
    }

    Boolean isItemNewEqualsOld(nitem, oitem) {

        nitem.needupdate['field'] = needUpdate(nitem.field, oitem.field)

        // if action='desc' check all
        if('desc' == nitem.utils['action']) {
            nitem.needupdate['category']    = needUpdate(nitem.category, oitem.category)
            nitem.needupdate['vendor']      = needUpdate(nitem.vendor, oitem.vendor)
            nitem.needupdate['desc']        = nitem.fdesc.size != oitem.fdesc.size
            nitem.needupdate['pref']        = needUpdate(nitem.pref, oitem.pref)
            nitem.needupdate['advert']      = needUpdate(nitem.advert, oitem.advert)
            nitem.needupdate['banner']      = needUpdate(nitem.banner, oitem.banner)
        }

        return nitem.needupdate.find { it.value } ? true : false
    }

    // if find defferent between new and old need update - return true
    Boolean needUpdate(newvalue, oldvalue) {

        def needupdate = [:]
        newvalue.each { name, value ->
            needupdate[name] = newvalue[name] != oldvalue[name]
        }
        return needupdate.find { it.value } ? true : false
    }

    def printXML(testitems) {

        def outp = new StringBuilder()
        testitems.item.each { item->
            outp << "<" << item.name() << " accwareid='" << item.@accwareid.text() << "' action='" << item.@action.text() << "'>\n"
            item.children().each { elm->
                outp << "\t<" << elm.name() << ">" << elm << "</" << elm.name() << ">\n"
            }
            outp << "</" << item.name() << ">\n"
        }
        println outp
    }

    String clean(s) {
	return s.toString().replaceAll(/\&/, '&amp;').replaceAll(/\"/, '&#34;').replaceAll(/\'/, '&#39;').replaceAll(/\n/, '').trim()
    }

    String cleanSpace(s) {
	return clean(s).replaceAll(/\p{Space}/, '')
    }

    String setLimitLength(s, len) {
	return s.length() > len ? s[0..len - 1] : s
    }

    Boolean getBoolean(field) {
	return field == '1' ? true : false
    }

    String getYesNo(field) {
	return field == '1' ? 'Y' : 'N'
    }

// <editor-fold defaultstate="collapsed" desc="()">

    def void doGet(HttpServletRequest request, HttpServletResponse response) {
        processRequest(request, response)
    }
    def void doPost(HttpServletRequest request, HttpServletResponse response) {
        processRequest(request, response)
    }
    String getServletInfo() {
        return "UploadXMLItems"
    }
// </editor-fold>

}

